package com.demo.function.spring.listener;

import com.alibaba.fastjson.JSON;
import com.demo.mapper.UserMapper;
import com.demo.model.dto.OrderHeader;
import com.demo.model.entity.User;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.PayloadApplicationEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

/**
 * 事件监听类，监听事务提交操作
 * @author cyj
 */
@Slf4j
@Component
public class ApplicationEventListener {

    @Resource
    private UserMapper userMapper;

    /**
     * 监听User对象保存到数据库并且提交事务后操作，建议配合@Async注解使用，用异步线程进行监听操作
     * 使用@TransactionalEventListener注解，必须要放在Spring管理的事务里才能有效果
     * @param event PayloadApplicationEvent事件
     * @throws InterruptedException 异常
     */
    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void afterCommitForUser(PayloadApplicationEvent<User> event) throws InterruptedException {
        User user = event.getPayload();
        log.info("ApplicationEventListener id = {}", user.getUserId());
        User existUser = userMapper.selectById(user.getId());
        log.info("从数据库查询的数据：" + JSON.toJSONString(existUser));

        existUser.setUserName("test");
        log.info("开始更新userName数据");
        userMapper.updateById(existUser);
    }

    /**
     * 多个事件监听，是否被抛异常事件{@link ApplicationEventListener#afterCommitForOrderHeaderException(PayloadApplicationEvent)}影响到正常运行
     * @param event PayloadApplicationEvent事件
     * @throws InterruptedException 异常
     */
    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void afterCommitForOrderHeader(PayloadApplicationEvent<OrderHeader> event) throws InterruptedException {
        log.info("事件1");
        Thread.sleep(1000L);
        log.info("ApplicationEventListener orderId = {}", event.getPayload().getOrderId());
    }

    /**
     * 多个事件监听，其中事件发生异常，是否影响另外一个事件{@link ApplicationEventListener#afterCommitForOrderHeader(PayloadApplicationEvent)}
     * @param event PayloadApplicationEvent事件
     * @throws InterruptedException 异常
     */
    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void afterCommitForOrderHeaderException(PayloadApplicationEvent<OrderHeader> event) throws InterruptedException {
        log.info("事件2");
        Thread.sleep(500L);
        throw new RuntimeException("ApplicationEventListener异常，orderId=" + event.getPayload().getOrderId());
    }

    /**
     * 在调用application命令之后触发监听器
     * @param event ApplicationReadyEvent事件
     */
    @EventListener
    public void readyEventListener(ApplicationReadyEvent event) {
        log.info("ApplicationReadyEvent listener：" + event);
    }

    /**
     * 测试异步监听器收到消息是否有顺序
     * @param event 事件
     * @throws InterruptedException 异常
     */
    @Async
    @EventListener
    public void orderlyEventListener(PayloadApplicationEvent<Integer> event) throws InterruptedException {
        Thread.sleep(5000L);
        log.info("event value：{}", event.getPayload());
    }
}
